{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "ae754c8d-cd39-413b-a24b-1be2d1891439",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import copy\n",
    "import matplotlib.pyplot as plt\n",
    "import h5py\n",
    "import scipy\n",
    "from PIL import Image\n",
    "from scipy import ndimage\n",
    "from public_tests import *\n",
    "import pandas as pd\n",
    "%matplotlib inline\n",
    "%load_ext autoreload\n",
    "%autoreload 2"
   ]
  },
  {
   "cell_type": "raw",
   "id": "62f1b9c2-2336-407a-92cb-5171cb739dff",
   "metadata": {},
   "source": [
    "获取数据集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "3e5c25bb-285f-474f-b7b6-572eb1cdb751",
   "metadata": {},
   "outputs": [],
   "source": [
    "def load_dataset():\n",
    "    # 加载训练集\n",
    "    train_dataset = h5py.File('datasets/train_catvnoncat.h5', \"r\")\n",
    "    train_set_x_orig = np.array(train_dataset[\"train_set_x\"][:])  # 训练集的特征\n",
    "    train_set_y_orig = np.array(train_dataset[\"train_set_y\"][:])  # 训练集的标签\n",
    "\n",
    "    # 加载测试集\n",
    "    test_dataset = h5py.File('datasets/test_catvnoncat.h5', \"r\")\n",
    "    test_set_x_orig = np.array(test_dataset[\"test_set_x\"][:])  # 测试集的特征\n",
    "    test_set_y_orig = np.array(test_dataset[\"test_set_y\"][:])  # 测试集的标签\n",
    "\n",
    "    # 加载类别信息\n",
    "    classes = np.array(test_dataset[\"list_classes\"][:])  # 类别信息（用于将标签映射到实际类别名称）\n",
    "\n",
    "    # 调整标签的形状，使其成为行向量\n",
    "    train_set_y_orig = train_set_y_orig.reshape((1, train_set_y_orig.shape[0]))\n",
    "    test_set_y_orig = test_set_y_orig.reshape((1, test_set_y_orig.shape[0]))\n",
    "\n",
    "    # 返回训练集、测试集和类别信息\n",
    "    return train_set_x_orig, train_set_y_orig, test_set_x_orig, test_set_y_orig, classes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "ceda90bd-d9a8-486d-b3ef-6ad4be6e766d",
   "metadata": {},
   "outputs": [],
   "source": [
    "train_set_x_orig, train_set_y, test_set_x_orig, test_set_y, classes = load_dataset()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "17c293b8-9508-4271-83a0-4865c7d6a9fb",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train_set_x_orig shape is (209, 64, 64, 3)\n",
      "train_set_x_orig[0] shape is (64, 64, 3)\n"
     ]
    }
   ],
   "source": [
    "print(f\"train_set_x_orig shape is {train_set_x_orig.shape}\")\n",
    "print(f\"train_set_x_orig[0] shape is {train_set_x_orig[0].shape}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "e9e4c2b1-e2b9-48eb-b63e-6c6dd6672ba4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x1b016cd1d90>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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Lh1DqVTC/v370djYiIGBAcyePRvd3d3jOlV3f3+/xjlO+DCMEdA4xxtjPU7nHAYGBjBz5kzE4/w5p+bcsOPxOGbNmgUAiMWO5mOZNGnSuJ7899A4xw8fhjECGud4YyzHWU1et5r7Ck4IIcSHAwUgIYQQQajpAJTJZHDHHXcgk8mE7soJReMcP3wYxghonOONUOOsORGCEEKIDwc1/QQkhBBi/KIAJIQQIggKQEIIIYKgACSEECIICkBCCCGCUNMBqLOzE3/0R3+Euro6LFmyBM8//3zoLh0Xzz77LC677DLMnDkTsVgMP/rRjyred87h9ttvx4wZM1BfX4/29nbs2bMnTGePkY6ODlxwwQVobGzE9OnTccUVV2D37t0VdYaHh7F69WpMnToVEydOxIoVK9Db2xuox8fG+vXrsWDBgvIvx9va2vDTn/60/P54GONI1q1bh1gshptuuqlcNh7G+bWvfQ2xWKziNX/+/PL742GM7/HWW2/hC1/4AqZOnYr6+np8/OMfx86dO8vvf9D3oJoNQP/2b/+GNWvW4I477sCLL76IhQsXYtmyZTh48GDorh0zg4ODWLhwITo7O833v/nNb+Lee+/F/fffjx07dmDChAlYtmwZhoeHP+CeHjtbt27F6tWrsX37djz11FPI5/P49Kc/jcHBwXKdm2++GZs3b8bGjRuxdetW7N+/H1deeWXAXvsza9YsrFu3Dl1dXdi5cycuueQSXH755XjttdcAjI8x/iEvvPACvve972HBggUV5eNlnGeffTYOHDhQfv385z8vvzdexvjOO+9g6dKlSKVS+OlPf4rXX38d//iP/4jJkyeX63zg9yBXo1x44YVu9erV5f8Xi0U3c+ZM19HREbBXYwcAt2nTpvL/S6WSa21tdXfddVe57NChQy6Tybh//dd/DdDDseHgwYMOgNu6datz7uiYUqmU27hxY7nO//zP/zgAbtu2baG6OSZMnjzZ/dM//dO4G+PAwIA7/fTT3VNPPeX+5E/+xN14443OufEzl3fccYdbuHCh+d54GaNzzn31q191F198MX0/xD2oJp+Acrkcurq60N7eXi6Lx+Nob2/Htm3bAvbsxLF371709PRUjLmpqQlLliw5qcfc19cHAJgyZQoAoKurC/l8vmKc8+fPx5w5c07acRaLRWzYsAGDg4Noa2sbd2NcvXo1PvOZz1SMBxhfc7lnzx7MnDkTp556Kq6++mrs27cPwPga449//GOcf/75+OxnP4vp06dj0aJFeOCBB8rvh7gH1WQAevvtt1EsFtHS0lJR3tLSgp6enkC9OrG8N67xNOZSqYSbbroJS5cuxTnnnAPg6DjT6TSam5sr6p6M49y1axcmTpyITCaD6667Dps2bcJZZ501rsa4YcMGvPjii+jo6Ii8N17GuWTJEjz88MN44oknsH79euzduxef+MQnMDAwMG7GCABvvvkm1q9fj9NPPx1PPvkkVq1ahS9/+ct45JFHAIS5B9VcOgYxfli9ejVeffXViu/TxxNnnHEGXn75ZfT19eHf//3fsXLlSmzdujV0t8aM7u5u3HjjjXjqqadQV1cXujsnjOXLl5f/vWDBAixZsgRz587FD3/4Q9TX1wfs2dhSKpVw/vnn4xvf+AYAYNGiRXj11Vdx//33Y+XKlUH6VJNPQKeccgoSiUREadLb24vW1tZAvTqxvDeu8TLm66+/Hj/5yU/ws5/9rJzfCTg6zlwuh0OHDlXUPxnHmU6n8dGPfhSLFy9GR0cHFi5ciG9/+9vjZoxdXV04ePAgzjvvPCSTSSSTSWzduhX33nsvkskkWlpaxsU4R9Lc3IyPfexjeOONN8bNXALAjBkzcNZZZ1WUnXnmmeWvG0Pcg2oyAKXTaSxevBhbtmwpl5VKJWzZsgVtbW0Be3bimDdvHlpbWyvG3N/fjx07dpxUY3bO4frrr8emTZvw9NNPY968eRXvL168GKlUqmKcu3fvxr59+06qcVqUSiVks9lxM8ZLL70Uu3btwssvv1x+nX/++bj66qvL/x4P4xzJ4cOH8atf/QozZswYN3MJAEuXLo38JOKXv/wl5s6dCyDQPeiESBvGgA0bNrhMJuMefvhh9/rrr7trr73WNTc3u56entBdO2YGBgbcSy+95F566SUHwH3rW99yL730kvvf//1f55xz69atc83Nze7xxx93r7zyirv88svdvHnz3NDQUOCeV8+qVatcU1OTe+aZZ9yBAwfKryNHjpTrXHfddW7OnDnu6aefdjt37nRtbW2ura0tYK/9ufXWW93WrVvd3r173SuvvOJuvfVWF4vF3H/+538658bHGC3+UAXn3PgY5y233OKeeeYZt3fvXvfcc8+59vZ2d8opp7iDBw8658bHGJ1z7vnnn3fJZNLdeeedbs+ePe7RRx91DQ0N7gc/+EG5zgd9D6rZAOScc9/5znfcnDlzXDqddhdeeKHbvn176C4dFz/72c8cgMhr5cqVzrmjMsjbbrvNtbS0uEwm4y699FK3e/fusJ32xBofAPfQQw+V6wwNDbm//uu/dpMnT3YNDQ3uz/7sz9yBAwfCdfoY+Ku/+is3d+5cl06n3bRp09yll15aDj7OjY8xWowMQONhnFdddZWbMWOGS6fT7iMf+Yi76qqr3BtvvFF+fzyM8T02b97szjnnHJfJZNz8+fPd97///Yr3P+h7kPIBCSGECEJN7gEJIYQY/ygACSGECIICkBBCiCAoAAkhhAiCApAQQoggKAAJIYQIggKQEEKIICgACSGECIICkBBCiCAoAAkhhAiCApAQQogg/P8lPIhuUcBIGQAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "pic0=train_set_x_orig[0]\n",
    "plt.imshow(pic0)"
   ]
  },
  {
   "cell_type": "raw",
   "id": "bf54e295-f80e-4373-8775-e33bb34f97bf",
   "metadata": {},
   "source": [
    "将原始数据进行格式转化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "a2e326d0-184e-4779-8c9d-d7ba28b25fb2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train_set_x_flatten shape is (12288, 209)\n",
      "test_set_x_flatten shape is (12288, 50)\n"
     ]
    }
   ],
   "source": [
    "train_set_x_flatten=train_set_x_orig.reshape(train_set_x_orig.shape[0],-1).T\n",
    "print(f\"train_set_x_flatten shape is {train_set_x_flatten.shape}\")\n",
    "test_set_x_flatten=test_set_x_orig.reshape(test_set_x_orig.shape[0],-1).T\n",
    "print(f\"test_set_x_flatten shape is {test_set_x_flatten.shape}\")"
   ]
  },
  {
   "cell_type": "raw",
   "id": "1efb9ddc-fcf2-4138-8287-4f1d8a0ec595",
   "metadata": {},
   "source": [
    "归一化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "6ee9dfee-7d36-498c-b372-434bf1e34f4d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train_set_x shape is (12288, 209)\n",
      "train_set_y is \n",
      " [[0 0 1 0 0 0 0 1 0 0 0 1 0 1 1 0 0 0 0 1 0 0 0 0 1 1 0 1 0 1 0 0 0 0 0 0\n",
      "  0 0 1 0 0 1 1 0 0 0 0 1 0 0 1 0 0 0 1 0 1 1 0 1 1 1 0 0 0 0 0 0 1 0 0 1\n",
      "  0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 0 0 1 1 1 0 0 1 0 0 0 0 1 0 1 0 1 1\n",
      "  1 1 1 1 0 0 0 0 0 1 0 0 0 1 0 0 1 0 1 0 1 1 0 0 0 1 1 1 1 1 0 0 0 0 1 0\n",
      "  1 1 1 0 1 1 0 0 0 1 0 0 1 0 0 0 0 0 1 0 1 0 1 0 0 1 1 1 0 0 1 1 0 1 0 1\n",
      "  0 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0]]\n"
     ]
    }
   ],
   "source": [
    "train_set_x = train_set_x_flatten / 255 # 输入矩阵 X\n",
    "print(f\"train_set_x shape is {train_set_x.shape}\")\n",
    "print(f\"train_set_y is \\n {train_set_y}\")# 输出lan\n",
    "test_set_x = test_set_x_flatten / 255. # 测试集用来检验模型准确率"
   ]
  },
  {
   "cell_type": "raw",
   "id": "9a475172-30fa-4f44-8933-4475bde27555",
   "metadata": {},
   "source": [
    "定义sigmoid"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "3c36377d-bf0e-4cab-8b61-abcfa7ed46b8",
   "metadata": {},
   "outputs": [],
   "source": [
    "def sigmoid(z):\n",
    "    s=1/(1+np.exp(-z))\n",
    "    return s\n",
    "\n",
    "def initialize_with_zeros(dim):   \n",
    "    w=np.zeros((dim,1))\n",
    "    b=0.0\n",
    "    return w, b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "d00effd3-6bde-4474-9947-0f0d088be75f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[92mAll tests passed!\n"
     ]
    }
   ],
   "source": [
    "sigmoid_test(sigmoid)"
   ]
  },
  {
   "cell_type": "raw",
   "id": "4aef863a-f2f3-40c7-ab60-8480af28dafe",
   "metadata": {},
   "source": [
    "传播函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "61fef252-6487-4cb9-a1df-ba9e2fb3128e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# X是输入矩阵（每个列向量对应一张图片），Y输出矩阵（列向量）\n",
    "def propagate(w, b, X, Y):\n",
    "    # 前向传播，计算损失函数\n",
    "    m = X.shape[1] #样本数量 12288 x 209 train_set_x\n",
    "    Y_hat = sigmoid(np.dot(w.T,X)+b) # Y_hat 是一个行向量,yhat向量\n",
    "    log_loss = -( np.dot(Y,np.log(Y_hat.T)) + np.dot((1-Y),np.log((1-Y_hat).T)) )/m #cost是通过numpy.ndarray计算得来，用词他的类型也是numpy.ndarray\n",
    "    \n",
    "    # 反向传播，计算梯度\n",
    "    dw=(np.dot(X,(Y_hat-Y).T))/m\n",
    "    db=np.sum(Y_hat-Y)/m\n",
    "    # YOUR CODE ENDS HERE\n",
    "    log_loss = np.squeeze(np.array(log_loss)) # 将cost转化为标量\n",
    "    \n",
    "    grads = {\"dw\": dw,\n",
    "             \"db\": db}\n",
    "    \n",
    "    return grads,log_loss"
   ]
  },
  {
   "cell_type": "raw",
   "id": "ecd516d6-fe30-40c7-b314-b373bb394a26",
   "metadata": {},
   "source": [
    "梯度下降函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "4387fb9c-9bb6-44f3-939a-c74ee4291594",
   "metadata": {},
   "outputs": [],
   "source": [
    "def gradient(w, b, X, Y, num_iterations=100, learning_rate=0.009, print_cost=False):\n",
    "    w = copy.deepcopy(w)\n",
    "    b = copy.deepcopy(b)\n",
    "    \n",
    "    costs = []\n",
    "    \n",
    "    for i in range(num_iterations):\n",
    "        # 计算梯度\n",
    "        grads, cost=propagate(w, b, X, Y)\n",
    "        dw = grads[\"dw\"]\n",
    "        db = grads[\"db\"]\n",
    "        \n",
    "        # 更新权重向量和偏置项\n",
    "        w=w-learning_rate*dw\n",
    "        b=b-learning_rate*db\n",
    "        costs.append(cost)\n",
    "        #每十次记录一次损失\n",
    "        # if i>0 and i%10 == 0:\n",
    "        #     costs.append(cost)\n",
    "        # 每一百次打印一次损失值\n",
    "        if i % 100 == 0 and print_cost:\n",
    "            print(\"Cost after iteration %i: %f\" % (i, cost))\n",
    "    \n",
    "    params = {\"w\": w,\n",
    "              \"b\": b}\n",
    "    \n",
    "    grads = {\"dw\": dw,\n",
    "             \"db\": db}\n",
    "    \n",
    "    return params, grads, costs"
   ]
  },
  {
   "cell_type": "raw",
   "id": "b4eb8108-62d8-41e1-9456-68dad7ae0602",
   "metadata": {},
   "source": [
    "预测值函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "415d8626-4f82-4adf-bc31-d0e41f169986",
   "metadata": {},
   "outputs": [],
   "source": [
    "def predict(w, b, X):\n",
    "    m = X.shape[1]\n",
    "    Y_prediction = np.zeros((1, m))\n",
    "    w = w.reshape(X.shape[0], 1)\n",
    "    \n",
    "    # A矩阵的值就是预测值，y hat。\n",
    "    yhat=sigmoid(np.dot(w.T,X)+b)\n",
    "    assert(yhat.shape==(1,X.shape[1]))\n",
    "    # YOUR CODE ENDS HERE\n",
    "    \n",
    "    for i in range(yhat.shape[1]):\n",
    "        \n",
    "        if yhat[0, i] > 0.5 :\n",
    "            Y_prediction[0,i] =1 \n",
    "        else:\n",
    "            Y_prediction[0,i] = 0\n",
    "    \n",
    "    return Y_prediction, yhat"
   ]
  },
  {
   "cell_type": "raw",
   "id": "f2ed1c3b-969e-4ca4-b1f9-382e21887991",
   "metadata": {},
   "source": [
    "函数汇总"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "88065db8-d402-4889-ba0e-be02230bdad1",
   "metadata": {},
   "outputs": [],
   "source": [
    "def model(X_train, Y_train, X_test, Y_test, num_iterations=2000, learning_rate=0.5, print_cost=False):\n",
    "    w, b = initialize_with_zeros(X_train.shape[0])\n",
    "    parameters, grads, costs = gradient(w, b, X_train, Y_train, num_iterations, learning_rate, print_cost)\n",
    "    w = parameters[\"w\"]\n",
    "    b = parameters[\"b\"]\n",
    "    Y_prediction_test, Y_hat_test = predict(w, b, X_test)\n",
    "    Y_prediction_train, Y_hat_train = predict(w, b, X_train)\n",
    "\n",
    "    # 打印训练集和测试集的错误率\n",
    "    if print_cost:\n",
    "        print(\"训练集准确率: {} %\".format(100 - np.mean(np.abs(Y_prediction_train - Y_train)) * 100))\n",
    "        print(\"测试集准确率: {} %\".format(100 - np.mean(np.abs(Y_prediction_test - Y_test)) * 100))\n",
    "\n",
    "    d = {\n",
    "        \"costs\": costs,\n",
    "        \"Y_prediction_test\": Y_prediction_test,\n",
    "        \"Y_hat_test\" : Y_hat_test,\n",
    "        \"Y_prediction_train\": Y_prediction_train, \n",
    "        \"Y_hat_train\" : Y_hat_train,\n",
    "        \"dw\" : grads[\"dw\"],\n",
    "        \"db\" : grads[\"db\"],\n",
    "        \"w\": w, \n",
    "        \"b\": b,\n",
    "        \"learning_rate\": learning_rate,\n",
    "        \"num_iterations\": num_iterations\n",
    "    }\n",
    "    \n",
    "    return d"
   ]
  },
  {
   "cell_type": "raw",
   "id": "8c5ea94b-fb8c-45c9-94d2-837f499cbfdd",
   "metadata": {},
   "source": [
    "建立模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "f7ba8c90-a270-4ddd-a3ee-2e2cf3fcf7ab",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Cost after iteration 0: 0.693147\n",
      "Cost after iteration 100: 0.584508\n",
      "Cost after iteration 200: 0.466949\n",
      "Cost after iteration 300: 0.376007\n",
      "Cost after iteration 400: 0.331463\n",
      "Cost after iteration 500: 0.303273\n",
      "Cost after iteration 600: 0.279880\n",
      "Cost after iteration 700: 0.260042\n",
      "Cost after iteration 800: 0.242941\n",
      "Cost after iteration 900: 0.228004\n",
      "Cost after iteration 1000: 0.214820\n",
      "Cost after iteration 1100: 0.203078\n",
      "Cost after iteration 1200: 0.192544\n",
      "Cost after iteration 1300: 0.183033\n",
      "Cost after iteration 1400: 0.174399\n",
      "Cost after iteration 1500: 0.166521\n",
      "Cost after iteration 1600: 0.159305\n",
      "Cost after iteration 1700: 0.152667\n",
      "Cost after iteration 1800: 0.146542\n",
      "Cost after iteration 1900: 0.140872\n",
      "训练集准确率: 99.04306220095694 %\n",
      "测试集准确率: 70.0 %\n"
     ]
    }
   ],
   "source": [
    "logistic_regression_model = model(train_set_x, train_set_y, test_set_x, test_set_y, num_iterations=2000, learning_rate=0.005, print_cost=True)"
   ]
  },
  {
   "cell_type": "raw",
   "id": "3f272092-c975-4a58-8df9-3a45b78bc9da",
   "metadata": {},
   "source": [
    "将输出保存到excel中"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "85507464-2bf8-4f25-a983-72bd053fc66c",
   "metadata": {},
   "outputs": [],
   "source": [
    "dw = logistic_regression_model[\"dw\"]\n",
    "dw_data = pd.DataFrame(dw,columns=[\"dw\"])\n",
    "\n",
    "w = logistic_regression_model[\"w\"]\n",
    "w_data = pd.DataFrame(w,columns=[\"w\"])\n",
    "\n",
    "costs = logistic_regression_model[\"costs\"]\n",
    "costs_data = pd.DataFrame(costs,columns=[\"costs\"])\n",
    "combined_df = pd.concat([dw_data, w_data, costs_data], axis=1)\n",
    "with pd.ExcelWriter(\"output2.xlsx\", engine='openpyxl') as writer:\n",
    "    combined_df.to_excel(writer, sheet_name='Sheet1', index=False)"
   ]
  },
  {
   "cell_type": "raw",
   "id": "02a200e7-b899-42c2-9297-13b90cf923f0",
   "metadata": {},
   "source": [
    "打印损失曲线图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9234c368-89e7-42b2-b780-870613e6f80e",
   "metadata": {},
   "outputs": [],
   "source": [
    "costs = np.squeeze(logistic_regression_model['costs'])\n",
    "plt.plot(costs)\n",
    "plt.ylabel('log_loss')\n",
    "plt.xlabel('iterations (per tens)')\n",
    "plt.title(\"Learning rate =\" + str(logistic_regression_model[\"learning_rate\"]))\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
